/* -*- mode: c++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */

#ifndef _PFS_H_
#define _PFS_H_

/* portable file system interfaces
 */

#include <stdlib.h>

#ifdef WIN32

#include <windows.h>

typedef TCHAR           char_type;

typedef HANDLE          file_handle_type;

#else

#include <sys/types.h>
#include <dirent.h>

typedef char            char_type;

typedef int             file_handle_type;

#endif

#include <string>
#include <vector>

#include <dybuf.h>

struct Path {
    char_type          *name;

    // in unit of char_type
    int                 size;

    // in unit of char_type
    int                 len;

    Path() : name(NULL), size(0), len(0)
    {
    }

    Path(const char_type *p);

    Path(const char_type *p, int l);

    ~Path();

    void to_target_platform();

    void assign(const char_type *p);

    void assign(const char_type *p, int l);

    bool assign_mbs(const char *p);

    bool assign_wcs(const wchar_t *p);

    bool get_mbs(char **buf, int *n) const;

    bool get_wcs(wchar_t **buf, int *n) const;
};

enum PfsOpenMode {
    POM_READ = 1,

    POM_WRITE = 2,

    POM_READWRITE = 4,

    POM_TRUNC = 8,

    /* 如果文件不存在，则创建 */
    POM_CREAT = 16,

    /* 只有当文件存在的时候打开，POM_CREAT 与 POM_OPEN_EXISTS 不能同时
     * 存在 */
    POM_OPEN_EXISTS = 32,
};

// valid file handle predicating.
#ifdef WIN32
#define PFS_VALID_HANDLE_P(H)   ((H) != INVALID_HANDLE_VALUE)

#define PFS_INVALID_HANDLE      (INVALID_HANDLE_VALUE)
#else
#define PFS_VALID_HANDLE_P(H)   ((H) >= 0)

#define PFS_INVALID_HANDLE      (-1)
#endif

typedef std::vector<Path *> Paths;

// not thread-safe
extern int pfs_errno;

// type for size
typedef unsigned long long      pfs_uint64;

typedef long long               pfs_int64;

extern int
pfs_list_dir(const Path& path, Paths& result);

extern file_handle_type
pfs_open(const Path& path, int flags, ...);

extern int
pfs_close(file_handle_type handle);

extern int
pfs_unlink(const Path& path);

/* ptr          buffer to fill
 * len          required length to read
 * return       the size has read
 */
extern pfs_int64
pfs_read(file_handle_type handle, void *ptr, pfs_int64 len);

/* ptr          buffer to write
 * len          required length to write
 * return       the size has writed
 */
extern pfs_int64
pfs_write(file_handle_type handle, const void *ptr, pfs_int64 len);

enum PfsSeekMethod {
    PSM_BEGIN,

    PSM_CURRENT,

    PSM_END,
};

/* pos          position accroding to method
 * method       seek method (PfsSeekMethod)
 * return       return the abs-position
 */
extern pfs_int64
pfs_seek(file_handle_type handle, pfs_int64 pos, int method);

/* return       return the size of file by handle
 */
extern pfs_int64
pfs_get_file_size(file_handle_type handle);

/* return       return the size of file by path
 */
extern pfs_int64
pfs_get_file_size(const Path& path);

/* desc         set the length of file size, and move the file positon
 *              to there
 */
extern bool
pfs_set_file_size(file_handle_type handle, pfs_int64 len);

extern bool
pfs_lock_entire(file_handle_type handle);

extern bool
pfs_unlock_entire(file_handle_type handle);

enum PfsFileType {
    PFT_REG,

    PFT_DIR,

    PFT_OTH,

    PFT_NOT_EXISTS,
};

extern PfsFileType
pfs_get_file_type(const Path& path);

extern DyBuf *
pfs_load_file(const Path& path);

#endif /* _PFS_H_ */
